﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Defect_Tracking_System.Models
{
    public class ReportManagement
    {
        private static ReportManagement instance;

        public static ReportManagement GetInstance()
        {
            if (instance == null)
            {
                instance = new ReportManagement();
            }
            return instance;
        }

        static DefectManagement Dm = DefectManagement.GetInstance();
        static ProjectManagement Pm = ProjectManagement.GetInstance();

        public interface ExportDocument
        {
            string[] Headers { get; }
            string[] ColumnsName { get; }
            IQueryable Datas { get; }
        }

        public class DefectDoc : ExportDocument
        {
            public string UserName;
            public string ProjectId;
            public string Type;
            public string KeyWord;
            public DefectDoc(string UserName, string ProjectId, string Type)
            {
                this.UserName = UserName;
                this.ProjectId = ProjectId;
                this.Type = Type;
            }

            public DefectDoc(string UserName, string keyWord)
            {
                this.KeyWord = keyWord;
                this.UserName = UserName;
            }

            public string[] Headers
            {
                get { return new string[] { "Defect Number", "Defect Title", "Description", "Project Name", "Created Date", "Diagnosis", "Creator", "Originator", "Type", "Version", "Priority", "Status", "Is Closed" }; }
            }

            public string[] ColumnsName
            {
                get { return new string[] { "DefectNumber", "DefectTitle", "Description", "ProjectName", "CreatedDate", "Diagnosis", "Creator", "OriginatorName", "Type", "Version", "Priority", "Status", "IsClose" }; }
            }

            public IQueryable Datas
            {
                get 
                { 
                    List<Defect> Li;
                    if (String.IsNullOrEmpty(KeyWord))
                    {
                        Li = Dm.GetDefects(ProjectId, UserName, Type).ToList();
                    }
                    else
                    {
                        Li = Dm.SearchDefect(KeyWord, UserName).ToList();
                    }
                    List<DefectModel> LiModel = new List<DefectModel>();
                    foreach (Defect D in Li)
                    {
                        DefectModel model = new DefectModel();
                        model.ProjectName = D.Project.ProjectName;
                        model.DefectNumber = D.DefectNumber;
                        model.DefectTitle = D.DefectTitle;
                        model.Type = D.Type;
                        model.Priority = D.Priority;
                        model.Status = D.Status;
                        model.CreatedDate = D.CreatedDate.ToString("MM/dd/yyyy hh:mm:ss");
                        model.Creator = D.AccountCreator.UserName;
                        model.Description = D.Description;
                        model.Diagnosis = D.Diagnosis;
                        model.OriginatorName = D.Client.FirstName + " " + D.Client.LastName + " - " + D.Client.Company;
                        model.IsClose = D.IsClosed;
                        model.Version = D.Version;
                        LiModel.Add(model);
                    }
                    return LiModel.AsQueryable();
                }
            }
        }

        public int GetNumberOpenDefect(DateTime Date, String ProjectId)
        {
            DefectTrackingSystemEntities Entities = new DefectTrackingSystemEntities();

            Date = Date.AddDays(1);
            Guid id;
            Guid.TryParse(ProjectId, out id);

            var Defects = from defect in Entities.Defects
                          where defect.ProjectId == id && defect.CreatedDate < Date
                          select defect;

            int Count = Defects.Count();

            foreach (Defect defect in Defects.ToList())
            {
                var ClosedLogs = from dl in Entities.DefectLogs
                                 where dl.Content.Contains("closed") && dl.CreatedTime < Date && dl.DefectId == defect.DefectId
                                 orderby dl.CreatedTime descending
                                 select dl;

                int TotalClosedLogs = ClosedLogs.Count();
                DefectLog ClosedLog = ClosedLogs.FirstOrDefault();

                if (TotalClosedLogs > 0)
                {
                    var ReopenedLogs = from dl in Entities.DefectLogs
                                     where dl.Content.Contains("reopened") && dl.CreatedTime < Date && dl.DefectId == defect.DefectId
                                     orderby dl.CreatedTime descending
                                     select dl;

                    var TotalReOpenedLogs = ReopenedLogs.Count();
                    DefectLog ReopenedLog = ReopenedLogs.FirstOrDefault();

                    if (TotalReOpenedLogs > 0)
                    {
                        if (ReopenedLog.CreatedTime < ClosedLog.CreatedTime)
                        {
                            Count--;
                        }                     
                    }
                    else
                    {
                        Count--;
                    }
                }
            }

            return Count;
        }

        public List<LineChartItem> GetLineChartProjectReport(DateTime From, DateTime To, String ProjectId)
        {
            List<LineChartItem> Items = new List<LineChartItem>();

            Project project = ProjectManagement.GetInstance().GetProjectById(ProjectId);

            if (project == null)
            {
                return Items;
            }

            for (int i = 0; From.Date.AddDays(i) <= To.Date; i++)
            {
                LineChartItem Item = new LineChartItem();
                DateTime Date = From.AddDays(i);
                Item.Year = Date.Year;
                Item.Month = Date.Month;
                Item.Day = Date.Day;
                Item.Data=GetNumberOpenDefect(Date, ProjectId);

                Items.Add(Item);
            }
            return Items;
        }

        public MasterChartModel GetMasterCharReport(DateTime From, DateTime To, String ProjectId)
        {
            MasterChartModel Model = new MasterChartModel();

            Project project = ProjectManagement.GetInstance().GetProjectById(ProjectId);

            if (project == null)
            {
                return Model;
            }
            
            Model.FromYear = From.Year;
            Model.FromMonth = From.Month;
            Model.FromYear = From.Year;
            Model.ToYear = To.Year;
            Model.ToMonth = To.Month;
            Model.ToDay = To.Day;

            for (int i = 0; From.Date.AddDays(i) <= To.Date; i++)
            {
                DateTime Date = From.AddDays(i);
                Model.Data.Add(GetNumberOpenDefect(Date, ProjectId));
            }

            return Model;
        }

        public List<PieChartItem> GetPieChartProjectReport(String TypeReport, String ProjectId)
        {
            DefectTrackingSystemEntities Entities = new DefectTrackingSystemEntities();

            List<PieChartItem> Items = new List<PieChartItem>();
            Guid id; 
            Guid.TryParse(ProjectId, out id);

            var Defects = from d in Entities.Defects
                          where d.ProjectId == id
                          select d;

            int TotalDefect = Defects.Count();

            if (TotalDefect > 0)
            {
                if (TypeReport == "DefectStatus")
                {
                    String[] Statuses = ProjectManagement.GetInstance().GetDefectStatuses(ProjectId);
                    foreach (String Status in Statuses)
                    {
                        var DefectWithStatus = from d in Entities.Defects
                                               where d.Status == Status && d.ProjectId == id
                                               select d;

                        int Count = DefectWithStatus.Count();

                        PieChartItem Item = new PieChartItem();
                        Item.Name = Status;
                        Item.Number = Count;
                        Item.Percent = Count * 100 / TotalDefect;
                        Items.Add(Item);
                    }
                }
                else if (TypeReport == "DefectPriority")
                {
                    String[] Priorities = ProjectManagement.GetInstance().GetDefectPriorities(ProjectId);

                    foreach (String Priority in Priorities)
                    {
                        var DefectWithPriority = from d in Entities.Defects
                                               where d.Priority == Priority && d.ProjectId == id
                                               select d;

                        int Count = DefectWithPriority.Count();

                        PieChartItem Item = new PieChartItem();
                        Item.Name = Priority;
                        Item.Number = Count;
                        Item.Percent = Count * 100 / TotalDefect;
                        Items.Add(Item);
                    }
                }
                else if (TypeReport == "DefectType")
                {
                    String[] Types = ProjectManagement.GetInstance().GetDefectTypes(ProjectId);

                    foreach (String Type in Types)
                    {
                        var DefectWithType = from d in Entities.Defects
                                               where d.Type == Type && d.ProjectId == id
                                               select d;

                        int Count = DefectWithType.Count();

                        PieChartItem Item = new PieChartItem();
                        Item.Name = Type;
                        Item.Number = Count;
                        Item.Percent = Count * 100 / TotalDefect;
                        Items.Add(Item);
                    }
                }
                else if (TypeReport == "ProjectVersion")
                {
                    String[] Versions = ProjectManagement.GetInstance().GetProjectVersions(ProjectId);

                    foreach (String Version in Versions)
                    {
                        var ProjectWithVersion = from d in Entities.Defects
                                               where d.Version == Version && d.ProjectId == id
                                               select d;

                        int Count = ProjectWithVersion.Count();

                        PieChartItem Item = new PieChartItem();
                        Item.Name = Version;
                        Item.Number = Count;
                        Item.Percent = Count * 100 / TotalDefect;
                        Items.Add(Item);
                    }
                }
            }

            return Items;
        }
    }

    public class PieChartItem
    {
        public String Name { get; set; }
        public int Number { get; set; }
        public float Percent { get; set; }
    }

    public class LineChartItem
    {
        public int Year { get; set; }
        public int Month { get; set; }
        public int Day { get; set; }
        public int Data { get; set; }
    }

    public class MasterChartModel
    {
        public int FromYear { get; set; }
        public int FromMonth { get; set; }
        public int FromDay { get; set; }

        public int ToYear { get; set; }
        public int ToMonth { get; set; }
        public int ToDay { get; set; }

        public List<int> Data;

        public MasterChartModel()
        {
            Data = new List<int>();
        }
    }
}